<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Painting in Qyoto II</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="GUI, painting, Qt, Qyoto, C#">
<meta name="description" content="In this chapter of the Qyoto tutorial, we
will continue with painting.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<div class="content">


<a href="/" title="Home">Home</a>&nbsp;
<a href="..">Contents</a>


<h1>Painting in Qyoto II</h1>

<p>
In this part of the Qyoto C# programming tutorial we will continue 
with painting. We will present some more complex examples.
</p>

<div class="center">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-9706709751191532";
/* top_horizontal */
google_ad_slot = "3327173442";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>

<h2>Donut Shape</h2>

<p>
The firs example creates a complex shape by 
rotating a bunch of ellipses. 
</p>

<pre class="code">
using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws a donut
 * shape.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Donut";

        PaintEvent += OnPaintEvent;
        
        Resize(350, 280);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs&lt;QPaintEvent&gt; e)
    {
        QPainter ptr = new QPainter(this);
        DrawDonut(ptr);
        
        ptr.End();
     }
    
    void DrawDonut(QPainter ptr) 
    {
        QColor col = new QColor();
        col.SetNamedColor("#333333");

        ptr.Pen = new QPen(col, 0.5);

        ptr.SetRenderHint(QPainter.RenderHint.Antialiasing);

        int h = Height;
        int w = Width;

        ptr.Translate(new QPoint(w/2, h/2));

         for (double rot=0; rot &lt; 360.0; rot+=5.0 ) 
         {
             ptr.DrawEllipse(-125, -40, 250, 80);
             ptr.Rotate(5.0);
         }
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}
</pre>

<p>
In this example, we create a donut. The shape resembles a cookie, 
hence the name donut. 
</p>

<pre class="explanation">
QColor color = new QColor();
color.SetNamedColor("#333333");
</pre>

<p>
We can use a hexadecimal notation to create a colour object. 
</p>

<pre class="explanation">
int h = Height;
int w = Width;
</pre>

<p>
Here we determine the width and height of the window. 
</p>

<pre class="explanation">
ptr.Translate(new QPoint(w/2, h/2));
</pre>

<p>
We move the coordinate system to the middle of the window. This way we
make the drawing mathematically easier. 
</p>

<pre class="explanation">
for (double rot=0; rot &lt; 360.0; rot+=5.0 ) 
{
    ptr.DrawEllipse(-125, -40, 250, 80);
    ptr.Rotate(5.0);
}
</pre>

<p>
We draw an ellipse object 72 times. Each time, we rotate the
ellipse by 5 degrees. This will create our donut shape.
</p>

<img src="/img/gui/sharpqyoto/donut.jpg" alt="Donut">
<div class="figure">Figure: Donut</div>



<h2>Grayscale image</h2>

<p>
In the following example, we will create a gray scale image.
</p>

<pre class="code">
using System;
using QtGui;
using QtCore;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this example, we create a 
 * grayscale image.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{    
    QImage sid;
    int w, h = 0;

    public QyotoApp() 
    {
        WindowTitle = "Gray scale";
         
        PaintEvent += OnPaintEvent;        

        LoadImage();
        Resize(320, 150);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs&lt;QPaintEvent&gt; e)
    { 
        QPainter ptr = new QPainter(this);
        DrawImages(ptr);
        
        ptr.End();
    }
    
    void DrawImages(QPainter ptr) 
    {
        ptr.DrawImage(5, 15, sid);
        ptr.DrawImage(w + 10, 15, GrayScale(sid.Copy()));
    }

    void LoadImage()
    {
        sid = new QImage("smallsid.jpg");

        w = sid.Width();
        h = sid.Height();
    }

    QImage GrayScale(QImage img)
    {        
        for (int i=0; i &lt; w; i++)
        {
            for (int j=0; j &lt; h; j++)
            {
                uint c = img.Pixel(i, j);
                int gray = Global.qGray(c);
                int alpha = Global.qAlpha(c);
                img.SetPixel(i, j, Global.qRgba(gray, gray, 
                   gray, alpha));                
            }
        }  

        return img;
    }          
    
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}
</pre>

<p>
We have a colour jpg image. We draw it on the window. We create a copy of
the image, convert it to gray scale and draw it on the window next to the
original image.
</p>


<pre class="explanation">
void LoadImage()
{
    sid = new QImage("smallsid.jpg");

    w = sid.Width();
    h = sid.Height();
}
</pre>

<p>
In the LoadImage() method we load the image and get its
width and height. 
</p>

<pre class="explanation">
QImage GrayScale(QImage img)
{        
    for (int i=0; i &lt; w; i++)
    {
        for (int j=0; j &lt; h; j++)
        {
            uint c = img.Pixel(i, j);
            int gray = Global.qGray(c);
            int alpha = Global.qAlpha(c);
            img.SetPixel(i, j, Global.qRgba(gray, gray, 
                gray, alpha));                
        }
    }  

    return img;
}    
</pre>

<p>
The <code>GrayScale()</code> method transforms an image to gray scale and returns it.
We go through all pixels of the image. The <code>Pixel()</code> method returns a pixel
in question. We use the <code>Global.qGray()</code> method to get the gray value of
the specific pixel. Similarly, we get the alpha value. Finally, we modify the
pixel with the <code>SetPixel()</code> method. We use the gray value for the red, green
and blue parts of the colour.
</p>


<img src="/img/gui/sharpqyoto/grayscale.jpg" alt="Grayscale image">
<div class="figure">Figure: Grayscale image</div>


<h2>Reflection</h2>

<p>
In the next example we show a reflected image. The effect makes
an illusion as if the image was reflected in water.
</p>

<pre class="code">
using System;
using QtGui;
using QtCore;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this example we create a reflected image.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{
    QImage img;
    QImage reflected_img;

    int iw, ih = 0;
    double initial_opacity = 0.7;
    double opacity = 0.7;
    double step = 0;
    const int GAP = 30;
    
    public QyotoApp() 
    {
        WindowTitle = "Reflection";
        
        PaintEvent += OnPaintEvent;

        InitExample();  

        Resize(300, 400);
        Move(150, 150);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs&lt;QPaintEvent&gt; e)
    { 
        QPainter ptr = new QPainter(this);
        DrawImages(ptr);
        
        ptr.End();
    }

    void InitExample()
    {
        img = new QImage("slanec.png");

        if (img.IsNull()) 
        {
            Console.WriteLine("Error loading image");
        }

        iw = img.Width();
        ih = img.Height();

        step = opacity / ih;    

        reflected_img = new QImage(iw, ih, QImage.Format.Format_RGB32);
        CreateReflectedImage();
    }       

    void CreateReflectedImage()
    {
        QPainter fptr = new QPainter(reflected_img);

        int i = 0;
        double opacity = 0.7;    

        while (i &lt; ih)
        {        
            i++;
            opacity = opacity - step;

            fptr.Opacity = initial_opacity-opacity;
            fptr.DrawImage(0, i, img, 0, i, -1, 1);
        }          

        fptr.End();
    }
    
    void DrawImages(QPainter ptr) 
    {
        int w = Width;
        int h = Height;

        ptr.FillRect(0, 0, w, h, Qt.GlobalColor.black);
        ptr.SetRenderHint(QPainter.RenderHint.Antialiasing);

        QRect r = new QRect(25, 15, iw, ih);
        ptr.DrawImage(r, img);

        ptr.Translate(0, 2 * ih + GAP);
        ptr.Scale(1, -1);     

        ptr.DrawImage(25, 0, reflected_img);      
    }
    
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}
</pre>

<p>
We load an image from the current working directory. 
We create another empty image of the same size. We copy
the original image to the new empty image line by line, applying
the gradually increasing transparency. 
</p>


<pre class="explanation">
img = new QImage("slanec.png");

if (img.IsNull()) 
{
    Console.WriteLine("Error loading image");
}
</pre>

<p>
We load a png image and do some error checking. 
</p>

<pre class="explanation">
iw = img.Width();
ih = img.Height();

step = opacity / ih;     
</pre>

<p>
We get the image width and height. The step variable controls 
the intensity of the fading out of second image. 
</p>

<pre class="explanation">
reflected_img = new QImage(iw, ih, QImage.Format.Format_RGB32);
</pre>

<p>
A new empty image is created. It has the size of the original
image. 
</p>

<pre class="explanation">
void CreateReflectedImage()
{
    QPainter fptr = new QPainter(reflected_img);
    ...
</pre>

<p>
In the CreateReflectedImage() method, we draw on the empty
image. 
</p>

<pre class="explanation">
while (i &lt; ih)
{        
    i++;
    opacity = opacity - step;

    fptr.Opacity = initial_opacity-opacity;
    fptr.DrawImage(0, i, img, 0, i, -1, 1);
}     
</pre>

<p>
We copy the original image to the new image. Line
by line. The opacity decreases by step each loop. 
</p>

<pre class="explanation">
QRect r = new QRect(25, 15, iw, ih);
ptr.DrawImage(r, img);
</pre>

<p>
The first image is drawn on the window. 
</p>

<pre class="explanation">
ptr.Translate(0, 2 * ih + GAP);
ptr.Scale(1, -1);     

ptr.DrawImage(25, 0, reflected_img);   
</pre>

<p>
Here we move the second image down, some space below the original one. The
<code>Scale()</code> method flips the image upside down. Note that the 
translation is twice the image height. This is necessary, because the scaling 
operation not only flips the image, but also moves the image up. To understand 
this, simply take a photograph, place it on the table and flip it.
</p>


<img src="/img/gui/sharpqyoto/reflection.jpg" alt="A reflected image">
<div class="figure">Figure: A reflected image</div>


<h2>Waiting effect</h2>

<p>
In this example, we use transparency effect to create a waiting demo. We
will draw 8 lines that will gradually fade out creating an illusion, that a
line is moving. Such effects are often used to inform users, that a lengthy
task is going on behind the scenes. An example is streaming video over the
Internet.
</p>

<pre class="code">
using System;
using QtGui;
using QtCore;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws basic shapes
 * available in Qyoto.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{
    int count = 0;
    
    double[,] trs = 
    {
        { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
        { 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
        { 0.9, 1.0,  0.0,  0.15, 0.3, 0.5, 0.65, 0.8 },
        { 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5, 0.65 },
        { 0.65, 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5 },
        { 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15, 0.3 },
        { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15 },
        { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0 }
    };
    
    public QyotoApp() 
    {
        WindowTitle = "Waiting";

        PaintEvent += OnPaintEvent;

        InitExample();
        
        Resize(300, 200);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs&lt;QPaintEvent&gt; e)
    {
        QPainter ptr = new QPainter(this);
        DrawLines(ptr);
        
        ptr.End();
    }
    
    void InitExample()
    {    
        count = 0;
        StartTimer(105);
    }

    void DrawLines(QPainter ptr)
    {
        QPen pen = new QPen();
        pen.Width = 3;
        pen.CapStyle = PenCapStyle.RoundCap;

        int w = Width;
        int h = Height;
       
        ptr.Translate(w/2, h/2);
        ptr.Pen = pen;

        int len = trs.GetLength(0);

        for (int i=0; i < len; i++)
        {
            ptr.Opacity = trs[count%8, i];
            ptr.DrawLine(0, -10, 0, -40);
            ptr.Rotate(45);
        }
    }

    protected override void OnTimerEvent(QTimerEvent e)
    {
        count++;
        Repaint();
    }
    
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}
</pre>

<p>
We draw eight lines with eight different alpha values.
</p>


<pre class="explanation">
double[,] trs = 
{
    { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
    { 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
...
</pre>

<p>
This is an array of transparency values. There are 8 rows, each for one
position. Each of the 8 lines will continuously use these values.
</p>

<pre class="explanation">
count = 0;
StartTimer(105);
</pre>

<p>
Here we initiate the count value and start a timer.
</p>

<pre class="explanation">
QPen pen = new QPen();
pen.Width = 3;
pen.CapStyle = PenCapStyle.RoundCap;
</pre>

<p>
We make the lines a bit thicker, so that they are more visible. We draw the
lines with rounded caps. Lines with rounded caps look better.
</p>

<pre class="explanation">
for (int i=0; i &lt; len; i++)
{
    ptr.Opacity = trs[count%8, i];
    ptr.DrawLine(0, -10, 0, -40);
    ptr.Rotate(45);
}
</pre>

<p>
In this loop, we set an opacity value. We draw the line and rotate it. This
creates an illusion of a moving and fading line.
</p>

<pre class="explanation">
protected override void OnTimerEvent(QTimerEvent e)
{
    count++;
    Repaint();
}
</pre>

<p>
Each time the timer event is called, we increase the count value and repaint
the window area.
</p>

<img src="/img/gui/sharpqyoto/waiting.png" alt="Waiting effect">
<div class="figure">Figure: Waiting effect</div>


<p>
In this part of the Qyoto C# programming tutorial, we finished talking about
painting in Qyoto. 
</p>

<div class="center">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<br>

<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>

<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified November 1, 2012  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->

</body>
</html>

